package com.wlz.dependencies;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wlz
 * @date 2022-05-25  9:07 下午
 */
public class MainStart {

	/**
	 * bean 定义
	 */
	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(16);

	/**
	 * 一级缓存
	 */
	public static Map<String,Object> singletonObjects = new ConcurrentHashMap<>();

	/**
	 * 二级缓存： 为了将 成熟Bean和纯净Bean分离，避免读取到不完整得Bean
	 */
	public static Map<String,Object> earlySingletonObjects=new ConcurrentHashMap<>();

	/**
	 * 三级缓存
	 */
	public static Map<String, ObjectFactory> singletonFactories=new ConcurrentHashMap<>();

	/**
	 *  循环依赖标识 正在创建的 bean
	 */
	public  static Set<String> singletonsCurrennlyInCreation=new HashSet<>();

	/**
	 *  模拟 读取 bean 定义
	 */
	public static void loadbeanDefinition() {
		RootBeanDefinition beanDefinitionA = new RootBeanDefinition(InstanceA.class);
		RootBeanDefinition beanDefinitionB = new RootBeanDefinition(InstanceB.class);
		beanDefinitionMap.put("instanceA", beanDefinitionA);
		beanDefinitionMap.put("instanceB", beanDefinitionB);
	}


	public static void main(String[] args) throws Exception {
		// 加载 BeanDefinition
		loadbeanDefinition();

		// 注册bean 的后置处理器

		// 创建bean
		for (String beanName : beanDefinitionMap.keySet()) {
			// 先创建A
			getBean(beanName);
		}
		InstanceA instanceA = (InstanceA)getBean("instanceA");
		instanceA.say();
		System.out.println(instanceA);

	}

	/**
	 *  获取bean
	 * @param beanName
	 * @return
	 */
	public static Object getBean(String beanName) throws Exception {
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}

		if (!singletonsCurrennlyInCreation.contains(beanName)) {
			singletonsCurrennlyInCreation.add(beanName);
		}

		// 实例化
		RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
		Class<?> beanClass = beanDefinition.getBeanClass();
		Object instanceBean = beanClass.newInstance(); // 通过无参构造函数实例化

		// 如果需要动态代理  创建动态代理 （耦合，BeanPostProcessor）
		// 动态代理创建有两种情况
		// 1. 存在循环依赖是 在 实例化之后创建动态代理
		// 2. 不存在循环依赖， 在 初始化之后创建 动态代理
//		instanceBean = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instanceBean,beanName);

		// 使用函数式接口
		singletonFactories.put(beanName, new ObjectFactory() {
			@Override
			public Object getObject() throws BeansException {
				return new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName),beanName); // todo  bug
			}
		});

		// 假设放到属性赋值的前面 ,虽然可以解决死循环调用问题，
		// 但是 如果此时另一个 线程也去getBean("instanceA") ,此时，instanceA 还未完成属性赋值(是不完整的bean) ,从而出现问题，此时就需要增加二级缓存
//		singletonObjects.put(beanName, instanceBean);  // 所以一级缓存不能放到这里
		// 使用二级缓存 存储, 使用二级缓存其实也可以解决循环依赖的问题
		// 但是 不易于扩展

		// 创建的动态代理，直接放到二级缓存，这时就不需要三级缓存了
		// 但是在这里 创建了动态代理，从而导致 初始化后创建的动态代理就没有用了
		// 此时 可以设置 只在循环依赖的情况下创建动态代理， 正常情况下还是在初始化之后创建动态代理

		// 如果 使用到了 对象工厂，二级缓存也不用在这里存储了
//		earlySingletonObjects.put(beanName, instanceBean);

		// 属性赋值
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 说明属性上有 @Autowired
			if (annotation != null) {
				declaredField.setAccessible(true);
				// byType byName
				Object filedObject = getBean(declaredField.getName()); // 获取B 的bean
				declaredField.set(instanceBean,filedObject);
			}
		}

		// 初始化 init-method 等


		// 由于 递归完后A 还是原实例 ，所以还是要从二级缓存中拿到proxy
		if (earlySingletonObjects.containsKey(beanName)) {
			instanceBean = earlySingletonObjects.get(beanName);
		}

		// 添加到一级缓存
		singletonObjects.put(beanName, instanceBean);
		// remove 二级缓存、三级缓存
		//
		return instanceBean;
	}

	public static Object getSingleton(String beanName) {
		// 先从一级缓存中拿
		Object object = singletonObjects.get(beanName);
		// 说明是循环依赖
		if (object == null && singletonsCurrennlyInCreation.contains(beanName)) {
			// 如果二级缓存中没有，再从三级缓存中拿
			object = earlySingletonObjects.get(beanName);
			if (object == null) {
				// 从三级缓存中拿
				ObjectFactory objectFactory = singletonFactories.get(beanName);
				if (objectFactory != null) {
					object = objectFactory.getObject(); // todo bug
					earlySingletonObjects.put(beanName,object);
				}
			}
		}
		return object;

	}


}
